<template>
	<div class="wind-select-mulity" v-fxClickOutSide="onClickOutSideHander">
		<el-popover
			ref="popper"
			v-model="popperVisible"
			placement="bottom-start"
			width="280"
			trigger="click"
			popper-class="wind-select-mulity__dropdown"
			:disabled="disabled"
			@show="onPoperShow"
		>
			<el-input
				ref="selectSearchInput"
				v-model="searchKey"
				placeholder="请输入"
				@keydown.down.native.prevent="navigateOptions('next')"
				@keydown.up.native.prevent="navigateOptions('pre')"
				@keyup.enter.native="onSelectEnter"
				@focus="onInputFocus"
				@blur="onInputBlur"
			>
				<i slot="prefix" class="el-input__icon el-icon-search"></i>
			</el-input>
			<div class="btn-tools" v-if="showTools">
				<el-button type="primary" size="mini" class="select-btn" @click="onSelectAll">全选</el-button>
				<el-button size="mini" class="select-btn" @click="onUnselectAll">取消全选</el-button>
			</div>
			<w-scroll-bar wrapClass="wind-select-mulity__dropdown-wrap">
				<ul class="wind-select-mulity__dropdown-list">
					<!-- <li
						:ref="`option-${emptyItem.id}`"
						v-show="currentOptionList.length!==0&&showEmpty"
						class='wind-select-mulity__dropdown-item'
						:class="selectItemClasses(emptyItem)"
						@click="onSelectItemClick(emptyItem)"
						@mouseover="onSelectItemMouseover(emptyItem)"
					>{{emptyItem.name}}</li> -->
					<li
						v-for="(item, index) in currentOptionList"
						:key="index"
						ref="option-item"
						class='wind-select-mulity__dropdown-item'
						:class="selectItemClasses(item)"
						@click="onSelectItemClick(item)"
						@mouseover="onSelectItemMouseover(item)"
					>{{item[optionProp.name]}}</li>
					<li v-show="currentOptionList.length===0" class='wind-select-mulity__dropdown-item'>无数据</li>
				</ul>
			</w-scroll-bar>
			<el-input
				ref="selectInput"
				slot="reference"
				readonly
				:placeholder="inputPlaceholder"
				:disabled="disabled"
				class="select-input"
				@click.native.prevent="onInputClick"
				@mouseenter.native="inputHovering = true"
				@mouseleave.native="inputHovering = false"
			>
				<template slot="suffix">
					<Icon v-show="!showClose" class="title-arrow__icon" :class="{
						'is-expanded': popperVisible
					}" type="arrow-down"></Icon>
					<i v-if="showClose" class="el-icon-circle-close select-input__clear-btn" @click="onClearClick"></i>
				</template>
			</el-input>
			<div v-show="currentTag" class="wind-select-mulity__tags" slot="reference">
				<w-tag
					v-show="currentTag"
					closable
					@close="onTagRemoveClick"
					@click="onTagClick"
				>{{currentTag && currentTag[optionProp.name]}}</w-tag>
				<el-popover
					:content="tagMoreText"
					placement="top-start"
					width="200"
					trigger="hover"
					popper-class="wind-select-mulity__tag-more-popper">
					<el-tag
						slot="reference"
						v-show="tagCount > 0"
						type="info"
						size="mini"
						class="select-tag"
						@click="onTagClick"
					>+{{tagCount}}个</el-tag>
				</el-popover>
			</div>
		</el-popover>
	</div>
</template>
<script>
/**
 * select by shang 2020/12/4
 * @desc select 选择框
 * @param {value}  [any] - 输入框值
 * @param {disabled}  [Boolean] - 是否禁用
 * @param {placeholder}  [String] - 默认提示
 * @param {filterKeys}  [Array] - 筛选keys
 * @param {optionlist}  [Array] - 选项集合
 * @param {fpBeforeSelect}  [Function] - 选择选项之后回调
 *
 * @event {change} 选项发生变化触发
 * @event {blur} 输入框失焦时触发
 * @event {focus} 输入框聚焦时触发
 */
import scrollIntoView from '../../js/utils/scroll-into-view.js'
import fxClickOutSide from '../../js/utils/clickoutside.js'
import { getTextWidth } from '../../js/utils/event.js'
import Icon from '../icon'
const SEARCH_PROPS = ['name', 'code', 'pinYin', 'pinYinList', 'label']
export default {
	name: 'w-select-mulity',
	components: {
		Icon
	},
	directives: {
		fxClickOutSide
	},
	props: {
		value: {
			type: Array,
			default: () => {
				return []
			}
		},
		disabled: Boolean,
		clearable: {
			type: Boolean,
			default: true
		},
		showEmpty: {
			type: Boolean,
			default: true
		},
		placeholder: {
			type: String,
			default: '请选择'
		},
		filterKeys: {
			type: Array,
			default: () => {
				return SEARCH_PROPS
			}
		},
		optionlist: {
			type: Array,
			default: () => {
				return []
			}
		},
		optionProp: {
			type: Object,
			default: () => {
				return {
					id: 'id',
					name: 'name',
					value: 'id',
					disabled: 'disabled'
				}
			}
		},
		fpBeforeSelect: {
			type: Function,
			default: () => {
				return Promise.resolve({})
			}
		},
		showTools: {
			type: Boolean,
			default: true
		}
	},
	data () {
		return {
			popperVisible: false,
			popperElm: null,
			currentValue: [],
			searchKey: '',
			sortOptionList: [],
			currentHoverItem: {},
			inputHovering: false,
			emptyItem: {
				id: 'empty',
				name: '空'
			},
			debounce: this.$fxUtils.debounce()
		}
	},
	computed: {
		currentOptionList () {
			return this.sortOptionList.filter(item => {
				return this.$fxUtils.fuzzyQueryObj(item, this.searchKey, this.filterKeys)
			})
		},
		selectItemClasses () {
			return (listItem) => {
				return {
					selected: this.currentValue.includes(listItem.id),
					hover: listItem.id === this.currentHoverItem.id
				}
			}
		},
		inputArrowIcon () {
			return this.popperVisible ? 'el-icon-arrow-up' : 'el-icon-arrow-down'
		},
		currentTag () {
			const _optionList = [this.emptyItem, ...this.optionlist]
			return _optionList.find(item => {
				return item.id === this.currentValue[0]
			})
		},
		tagCount () {
			return this.currentValue.includes(this.emptyItem.id) ? 0 : this.currentValue.length - 1
		},
		tagMoreText () {
			if (this.currentValue.length > 1) {
				const [first, ...moreList] = this.currentValue
				console.log(first)
				return moreList.map(item => {
					return this.optionlist.find(optionItem => {
						return optionItem.id === item
					}).name
				}).join('，')
			} else {
				return ''
			}
		},
		inputPlaceholder () {
			return this.currentValue.length > 0 ? '' : this.placeholder
		},
		showClose () {
			const hasValue = Array.isArray(this.value) && this.value.length > 0
			return this.clearable && !this.disabled && this.inputHovering && hasValue
		}
	},
	watch: {
		value: {
			immediate: true,
			handler (val, oldVal) {
				this.currentValue = val
			}
		},
		currentValue: {
			immediate: true,
			handler (val, oldVal) {
				this.$emit('input', val)
			}
		},
		popperVisible (val) {
			this.$emit('visible-change', val)
		},
		searchKey (val) {
			if (val) {
				this.debounce(200, false).then(() => {
					this.$nextTick(() => {
						if (this.currentOptionList.length === 1) {
							this.currentHoverItem = this.currentOptionList[0]
						}
					})
				})
			}
		}
	},
	methods: {
		onPoperShow () {
			this.popperElm = this.$refs.popper.$refs.popper
			this.searchKey = ''
			if (this.optionlist.length > 0) {
				this.sortOptionList = [...this.optionlist.filter(item => {
					return this.currentValue.includes(item.id)
				}), ...this.optionlist.filter(item => {
					return !this.currentValue.includes(item.id)
				})]
			} else {
				this.sortOptionList = []
			}
			if (this.currentOptionList.length > 0) {
				this.currentHoverItem = this.currentOptionList.find(item => {
					return this.currentValue.includes(item.id)
				}) || this.currentOptionList[0]
			}
			this.onSearchInputFocus()
		},
		onSearchInputFocus () {
			return new Promise(resolve => {
				if (this.popperVisible === true) {
					setTimeout(() => {
						this.$refs.selectSearchInput.focus()
						resolve()
					}, 100)
				}
			})
		},
		onClickOutSideHander () {
			if (this.popperVisible) {
				this.popperVisible = false
			}
		},
		onSelectItemClick (item) {
			this.onSearchInputFocus()
			return this.fpBeforeSelect(item).then(() => {
				if (item.id === this.emptyItem.id) {
					this.doEmptySelect(item)
				} else {
					this.doItemSelect(item)
				}
				this.$emit('change', this.currentValue)
				return Promise.resolve()
			})
		},
		doItemSelect (item) {
			if (this.currentValue.includes(item.id)) {
				this.currentValue = this.currentValue.filter(currentItem => {
					return currentItem !== item.id
				})
			} else {
				if (this.currentValue.includes(this.emptyItem.id)) {
					this.currentValue = []
				}
				this.currentValue.push(item.id)
			}
		},
		doEmptySelect (item) {
			if (this.currentValue.includes(item.id)) {
				this.currentValue = []
			} else {
				this.currentValue = [item.id]
			}
		},
		onSelectItemMouseover (item) {
			const target = event.target
			const text = target.innerText
			if (getTextWidth(text) > 280 && !target.title) {
				target.title = text
			}
			this.currentHoverItem = item
		},
		onTagRemoveClick () {
			this.currentValue.splice(0, 1)
			this.$emit('change', this.currentValue)
			this.onSearchInputFocus()
		},
		onTagClick () {
			this.onSearchInputFocus()
			this.popperVisible = true
		},
		onInputClick () {
			this.onSearchInputFocus()
		},
		onSelectAll () {
			// this.currentValue = this.currentOptionList.map(item => {
			// 	return item.id
			// })
			this.currentOptionList.forEach(item => {
				const filterIndex = this.currentValue.findIndex(value => {
					return value === item.id
				})
				if (filterIndex === -1) {
					this.currentValue.push(item.id)
				}
			})
			this.$emit('change', this.currentValue)
		},
		onUnselectAll () {
			// this.currentValue = []
			this.currentOptionList.forEach(item => {
				const filterIndex = this.currentValue.findIndex(value => {
					return value === item.id
				})
				if (filterIndex !== -1) {
					this.currentValue.splice(filterIndex, 1)
				}
			})
			this.$emit('change', this.currentValue)
		},
		navigateOptions (type) {
			if (this.currentOptionList.length === 0 || !this.popperVisible) {
				return false
			}
			const _optionList = this.showEmpty ? [this.emptyItem, ...this.currentOptionList] : this.currentOptionList
			let index = _optionList.findIndex(item => {
				return item === this.currentHoverItem
			})
			if (~index) {
				if (type === 'next') {
					if (index === _optionList.length - 1) {
						index = 0
					} else {
						index = index + 1
					}
				} else {
					if (index === 0) {
						index = _optionList.length - 1
					} else {
						index = index - 1
					}
				}
				this.currentHoverItem = _optionList[index]
			} else {
				this.currentHoverItem = _optionList[0]
			}
			this.$nextTick(() => this.scrollToOption(this.currentHoverItem))
		},
		scrollToOption (optionItem) {
			let target = null
			if (optionItem.id === this.emptyItem.id) {
				target = this.$refs[`option-${this.emptyItem.id}`]
			} else {
				const index = this.currentOptionList.findIndex(item => {
					return item.id === optionItem.id
				})
				target = this.$refs['option-item'][index]
			}
			if (target) {
				const menu = this.$refs.popper.$refs.popper.querySelector('.wind-select-mulity__dropdown-wrap')
				scrollIntoView(menu, target)
			}
		},
		onSelectEnter (event) {
			if (!this.popperVisible) {
				return false
			}
			this.onSelectItemClick(this.currentHoverItem).then(() => {
				if (event.ctrlKey) {
					this.popperVisible = false
					this.$emit('on-select-enter', event, this.currentValue)
				} else if (event.shiftKey) {
					this.$emit('on-select-enter', event, this.currentValue)
				}
			})
		},
		focus () {
			this.popperVisible = true
		},
		onClearClick () {
			this.onUnselectAll()
		},
		onInputFocus (e) {
			this.$emit('focus', e)
		},
		onInputBlur (e) {
			this.$emit('blur', e)
		}
	}
}
</script>
<style lang="stylus" scoped>
.wind-select-mulity {
	display: inline-block;
    position: relative;
	.select-input {
		>>>.el-input__inner {
			cursor: pointer
		}
		.title-arrow__icon {
			width: 10px
			height:10px
			margin-right: 5px
			transition: transform 0.3s;
			&.is-expanded {
				transform: rotate(-180deg);
			}
		}
		&__clear-btn {
			font-size: 14px
		}
	}
	&__tags {
		position: absolute;
		line-height: normal;
		white-space: normal;
		z-index: 1;
		top: 50%;
		transform: translateY(-50%);
		display: flex;
		align-items: center;
		flex-wrap: wrap;
		.select-tag {
			box-sizing: border-box;
			border-color: transparent;
			margin: 2px 0 2px 6px;
			background-color: #318cf2;
			color: #fff;
			user-select:none;
			>>>.el-tag__close.el-icon-close {
				background-color: #C0C4CC;
			}
		}
	}
	&__dropdown {
		&-list {
			list-style: none;
			padding: 6px 0;
			margin: 0;
			box-sizing: border-box;
		}
		&-item {
			font-size: 12px;
			padding: 0 20px 0 0
			position: relative;
			white-space: nowrap;
			overflow: hidden;
			text-overflow: ellipsis;
			color: #606266;
			height: 34px;
			line-height: 34px;
			box-sizing: border-box;
			cursor: pointer;
			&.hover, &:hover {
				background-color: #F5F7FA;
			}
			&.selected {
				color: #409EFF;
				font-weight: 700;
				&::after {
					position: absolute;
					right: 0px;
					font-family: element-icons;
					content: "\e6da";
					font-size: 12px;
					font-weight: 700;
					-webkit-font-smoothing: antialiased;
				}
			}
		}
		.btn-tools {
			height: 36px
			line-height: 36px
			.select-btn {
				padding: 4px 15px
			}
		}
	}
}
</style>
<style lang="stylus">
.wind-select-mulity__dropdown {
	&-wrap {
		height: 274px;
	}
}
.wind-select-mulity__tag-more-popper {
	font-size: 12px
}
</style>
